package com.lv.thumb.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lv.thumb.constant.ThumbConstant;
import com.lv.thumb.model.dto.thumb.DoThumbRequest;
import com.lv.thumb.model.entity.Blog;
import com.lv.thumb.model.entity.Thumb;
import com.lv.thumb.model.entity.User;
import com.lv.thumb.service.BlogService;
import com.lv.thumb.service.ThumbService;
import com.lv.thumb.mapper.ThumbMapper;
import com.lv.thumb.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pulsar.shade.io.swagger.annotations.ApiOperation;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

/**
 *  点赞服务实现类
 *
 *  @author lv
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb> implements ThumbService {

    /**
     * 用户服务
     */
    private final UserService userService;

    /**
     * 博客服务
     */
    private final BlogService blogService;

    /**
     * 事务模板
     */
    private final TransactionTemplate transactionTemplate;

    /**
     * Redis 模板
     */
    private final RedisTemplate<String, Object> redisTemplate;
    /**
     *  点赞
     * @param doThumbRequest 点赞请求
     * @param request 请求
     * @return 点赞结果
     * @author lv
     * @throws RuntimeException 参数错误
     */
    @Override
    public Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
        log.info("doThumbRequest:{}", doThumbRequest);
        //1.校验参数是否为空
        if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
            throw new RuntimeException("参数错误");
        }
        //2.获取登录用户信息
        User loginUser = userService.getLoginUser(request);

        // 对当前登录用户的 ID 进行加锁，确保同一用户在同一时间只能执行一次点赞操作
        // 保证用户点赞的唯一性，防止用户重复点赞
       // intern() 方法确保相同的用户 ID 使用同一个字符串对象，保证锁的有效性。
        synchronized (loginUser.getId().toString().intern()) {

            // 编程式事务  保证点赞和更新博客的操作要么都成功，要么都失败
            return transactionTemplate.execute(status -> {
                // 3.判断用户是否已经点赞
                Long blogId = doThumbRequest.getBlogId();
                // 检查当前用户是否已经对该博客进行了点赞
                boolean exists = this.lambdaQuery()
                        .eq(Thumb::getUserId, loginUser.getId())
                        .eq(Thumb::getBlogId, blogId)
                        .exists();
                if (exists) {
                    log.warn("用户 {} 已对博客 {} 点赞", loginUser.getId(), blogId);
                    throw new RuntimeException("用户已点赞");
                }

                // 4.更新博客点赞数
                // 执行更新操作，将博客的点赞数加一
                // 注意：这里使用了 lambdaUpdate() 方法来构建更新条件和更新字段
                boolean update = blogService.lambdaUpdate()
                        .eq(Blog::getId, blogId)
                        .setSql("thumbCount = thumbCount + 1")
                        .update();

                // 5.插入点赞记录
                Thumb thumb = new Thumb();// 创建点赞对象
                thumb.setUserId(loginUser.getId());
                thumb.setBlogId(blogId);

                // 更新成功才执行
                return update && this.save(thumb);// 保存点赞记录
            });
        }
    }


    /**
     * 取消点赞
     * @param doThumbRequest 点赞请求
     * @param request   请求
     * @return  {@link Boolean }
     * @author lv
     */
    @Override
    public Boolean undoThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
        //1.校验参数是否为空
        if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
            throw new RuntimeException("参数错误");
        }
        //2.获取登录用户信息
        User loginUser = userService.getLoginUser(request);
        // 加锁
        synchronized (loginUser.getId().toString().intern()) {

            // 检查当前用户是否已经对该博客进行了点赞
            // 编程式事务
            return transactionTemplate.execute(status -> {
                Long blogId = doThumbRequest.getBlogId();
                Thumb thumb = this.lambdaQuery()
                        .eq(Thumb::getUserId, loginUser.getId())
                        .eq(Thumb::getBlogId, blogId)
                        .one();
                if (thumb == null) {
                    throw new RuntimeException("用户未点赞");
                }
                // 执行更新操作，将博客的点赞数减一
                // 注意：这里使用了 lambdaUpdate() 方法来构建更新条件和更新字段
                boolean update = blogService.lambdaUpdate()
                        .eq(Blog::getId, blogId)
                        .setSql("thumbCount = thumbCount - 1")
                        .update();

                // 更新成功才执行,删除点赞记录
                return update && this.removeById(thumb.getId());
            });
        }
    }


    /**
     *  是否点赞
     * @param blogId   博客id
     * @param userId   用户id
     * @return {@link Boolean }
     * @author lv
     */
    @ApiOperation( value = "是否点赞", notes = "是否点赞")
    @Override
    public Boolean hasThumb(Long blogId, Long userId) {
        return redisTemplate.opsForHash().hasKey(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString());
    }


}


